package com.dd.probe.web.service.task;

import com.dd.probe.common.pojo.BO.HostInfoBO;
import com.dd.probe.common.pojo.param.SSHConnParam;
import com.dd.probe.web.config.exception.DomainException;
import com.dd.probe.web.service.task.taskApi.ServerMetricsTask;
import com.dd.probe.web.util.ConfigConstants;
import com.dd.probe.web.util.SSHUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.lang.management.ManagementFactory;
import java.lang.management.OperatingSystemMXBean;
import java.net.InetAddress;
import java.util.concurrent.*;

/**
 * @Author liuxianmeng
 * @CreateTime 2024/12/22 11:59
 * @Description 服务器指标定时任务
 */
@Slf4j
@Component
public class ServerInfoBOTask implements ServerMetricsTask {

    public static HostInfoBO hostInfoBO = new HostInfoBO();

    @Override
    @Scheduled(fixedRate = 15 * 1000, initialDelay = 0)
    public void updateHostInfoBO() {
        try {
            // 初始化线程池
            ExecutorService executorService = Executors.newFixedThreadPool(7);

            // 线程 1：操作系统信息
            Future<?> osFuture = executorService.submit(() -> {
                OperatingSystemMXBean osBean = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
                hostInfoBO.setOsName(osBean.getName());
                hostInfoBO.setOsVersion(osBean.getVersion());
                try {
                    hostInfoBO.setHostName(InetAddress.getLocalHost().getHostName());
                } catch (Exception e) {
                    log.error(e.getMessage());
                }
            });

            // 线程 2：内存信息
            Future<?> memoryFuture = executorService.submit(() -> {
                try {
                    //com.sun.management.OperatingSystemMXBean osBean = (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
                    //// 获取总物理内存大小（单位：字节）
                    //long totalPhysicalMemory = osBean.getTotalPhysicalMemorySize();
                    //// 获取可用物理内存大小（单位：字节）
                    //long freePhysicalMemory = osBean.getFreePhysicalMemorySize();
                    //// 计算已使用物理内存大小（单位：字节）
                    //long usedPhysicalMemory = totalPhysicalMemory - freePhysicalMemory;

                    String memoryInfoStr = SSHUtil.execCommand("free -m");
                    String[] memoryInfoLines = memoryInfoStr.split("\n");
                    String memoryLine = memoryInfoLines[1].trim();
                    String[] memoryValues = memoryLine.split("\\s+");
                    hostInfoBO.setMemoryTotal(Long.parseLong(memoryValues[1]));
                    hostInfoBO.setMemoryUsed(Long.parseLong(memoryValues[2]));
                    hostInfoBO.setMemoryFree(Long.parseLong(memoryValues[3]));
                    hostInfoBO.setAvailableMemory(Long.parseLong(memoryValues[6]));
                } catch (Exception e) {
                    log.error(e.getMessage());
                }
            });

            // 线程 3：CPU信息
            Future<?> cpuFuture = executorService.submit(() -> {
                OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
                hostInfoBO.setCoreCount(osBean.getAvailableProcessors());
                String cpuInfoStr = SSHUtil.execCommand("lscpu | grep 'Model name'");
                String cpuModel = cpuInfoStr.split(":")[1].trim();
                hostInfoBO.setCpuModel(cpuModel);
            });

            // 线程 4：磁盘信息
            Future<?> diskFuture = executorService.submit(() -> {
                String diskInfoStr = SSHUtil.execCommand("df -h");
                String[] diskInfoLines = diskInfoStr.split("\n");
                // 正则表达式，用于匹配物理磁盘路径名
                String diskRegex = "^/dev/(sd|hd|vd|nvme|mmcblk)[a-z]+[0-9]*$";
                java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(diskRegex);
                int diskTotal = 0;
                int diskUsed = 0;
                int diskFree = 0;
                // 查找匹配实际磁盘文件系统名的infoLine
                for(String infoLine : diskInfoLines) {
                    String[] diskValues = infoLine.split("\\s+");
                    java.util.regex.Matcher matcher = pattern.matcher(diskValues[0]);
                    if (matcher.matches()) {
                        diskTotal += Integer.parseInt(diskValues[1].split("G")[0]);
                        diskUsed += Integer.parseInt(diskValues[2].split("G")[0]);
                        diskFree += Integer.parseInt(diskValues[3].split("G")[0]);
                    }
                }

                hostInfoBO.setDiskTotal(diskTotal);
                hostInfoBO.setDiskUsed(diskUsed);
                hostInfoBO.setDiskFree(diskFree);
            });

            // 线程 5：网络信息
            Future<?> networkFuture = executorService.submit(() -> {
                try {
                    // 要监控的网络接口，可根据实际情况修改 eth0 | ens33
                    String netIFaceName = ConfigConstants.NET_INTERFACE_NAME;
                    String commandRst =  SSHUtil.execCommand("sar -n DEV 1 2 | grep " + netIFaceName + " | awk '{print $4, $5}'");
                    String[] allRxTxInfo = commandRst.split("\\n"); // "187.00 63.98\n190.10 54.65\n188.56 59.29"
                    String realAvgRTxInfo = allRxTxInfo[2]; // 188.56 59.29
                    hostInfoBO.setRxBytesRate(Double.parseDouble(realAvgRTxInfo.split(" ")[0]) ); // 188.56kB/s
                    hostInfoBO.setTxBytesRate(Double.parseDouble(realAvgRTxInfo.split(" ")[1])); // 59.29kB/s
                } catch (Exception e) {
                    log.error(e.getMessage());
                }
            });

            // 线程 6：系统负载信息
            Future<?> loadFuture = executorService.submit(() -> {
                String loadAverageInfo = SSHUtil.execCommand("uptime");
                String[] loadAverageParts = loadAverageInfo.split(", ");
                hostInfoBO.setLoadAverage1Minute(Double.parseDouble(loadAverageParts[3].split(":")[1].trim()));
                hostInfoBO.setLoadAverage5Minutes(Double.parseDouble(loadAverageParts[4].trim()));
                hostInfoBO.setLoadAverage15Minutes(Double.parseDouble(loadAverageParts[5].trim()));
            });

            // 线程 7：系统启动时长信息
            Future<?> uptimeFuture = executorService.submit(() -> {
                long uptimeMillis = ManagementFactory.getRuntimeMXBean().getUptime();
                hostInfoBO.setSystemUptimeDays((int) (uptimeMillis / (1000 * 60 * 60 * 24)));
            });

            // 线程 8：CPU 负载信息
            Future<?> cpuLoadFuture = executorService.submit(() -> {
                try {
                    com.sun.management.OperatingSystemMXBean osBean = (com.sun.management.OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
                    // 获取系统 CPU 负载
                    double systemCpuLoad = osBean.getSystemCpuLoad();
                    hostInfoBO.setCpuLoad(systemCpuLoad);
                } catch (Exception e) {
                    log.error(e.getMessage());
                }
            });

            // 等待所有任务完成
            osFuture.get();
            memoryFuture.get();
            cpuFuture.get();
            diskFuture.get();
            networkFuture.get();
            loadFuture.get();
            uptimeFuture.get();
            cpuLoadFuture.get();

            executorService.shutdown();
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }
}
